﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using CommandLineParser.Exceptions;
using uTILLIty.ADExtractor.Properties;

namespace uTILLIty.ADExtractor
{
	class Program
	{
		private static readonly Dictionary<string, Type> RegisteredExporters = new Dictionary<string, Type>
		                                                       	{
		                                                       		{"CSV", typeof (CsvExportCommand)},
		                                                       		{"SQL", typeof (SqlExportCommand)},
		                                                       	};
		static int Main(string[] args)
		{
			FileVersionInfo fileInfo = FileVersionInfo.GetVersionInfo(typeof(Program).Assembly.Location);

			var parser = new CommandLineParser.CommandLineParser
			{
				ShowUsageHeader = string.Format("\n\n\n### {0} V. {1} ####################\n", fileInfo.ProductName, fileInfo.ProductVersion),
				ShowUsageFooter = "",
				AcceptSlash = true,
				ShowUsageOnEmptyCommandline = false,
				CheckMandatoryArguments = true,
				IgnoreCase = true,
				AcceptEqualSignSyntaxForValueArguments = true,
			};

			try
			{
				string[] effectiveArgs;
				var command = GetExporter(args, out effectiveArgs);
				parser.ShowUsageFooter = Prepend(command.GetAdditionalHelpText(), parser.ShowUsageFooter);
				parser.ExtractArgumentAttributes(command);

				if (args.Any(a => a == "/?") || args.Length == 0)
					throw new CommandLineException(string.Format(Resources.InvalidCommandlineArgs, string.Join("|", RegisteredExporters.Keys), Path.GetFileName(fileInfo.FileName)));

				parser.ParseCommandLine(effectiveArgs);

				if (!command.Silent)
					Console.WriteLine(parser.ShowUsageHeader);

				var retVal = command.Execute();
				if (retVal != 0)
				{
					//Console.WriteLine("Return-Value: {0}", retVal);
					parser.ShowParsedArguments();
				}
				return retVal;
			}
			catch (CommandLineException e)
			{
				parser.ShowUsage();
				Console.Error.WriteLine(Resources.ErrorMessageConsolePrefix, e.Message);
				return -3;
			}
			catch (Exception e)
			{
#if DEBUG
				if (Debugger.IsAttached)
					throw;
#endif
				TryWriteException(e);
				Exception ex = e;
				while (ex.InnerException != null)
					ex = ex.InnerException;

				Console.Error.WriteLine(Resources.ErrorMessageConsolePrefix, e.Message);
				//Console.Error.WriteLine("{0} ({1})", ex.Message, ex.GetType().Name);
				return -4;
			}
		}

		private static string Prepend(string stringToAdd, string existing)
		{
			if (!string.IsNullOrWhiteSpace(existing))
				return stringToAdd + "\n" + existing;
			return stringToAdd;
		}

		private static void TryWriteException(Exception exception)
		{
			var logfile = new FileInfo(string.Format("error_{0:ddMMyyHHmmss}.log", DateTime.Now));
			try
			{
				var exText = ExceptionToString(exception);
				File.WriteAllText(logfile.FullName, exText);
				Console.WriteLine(Resources.ErrorLoggedTo, logfile.FullName);
			}
			catch(Exception ex)
			{
				Console.WriteLine(Resources.ErrorCreatingErrorLog, logfile.FullName, ex.Message);				
			}
		}

		private static string ExceptionToString(Exception exception)
		{
			var exText = new StringBuilder(1024);
			exText.AppendLine(exception.ToString());
			exText.AppendLine();
			foreach (var key in exception.Data.Keys)
			{
				exText.AppendFormat("\t{0}: {1}", key, exception.Data[key]);
				exText.AppendLine();
				exText.AppendLine();
			}
			return exText.ToString();
		}

		private static ExportCommandBase GetExporter(string[] args, out string[] effectiveArgs)
		{
			var exporterType = RegisteredExporters.First().Value;
			effectiveArgs = args;

			if (args.Length > 0)
			{
				var argPrefixes = new[] {'-', '/'};
				if (!argPrefixes.Any(a => a == args[0][0]))
				{
					var key = args[0].ToUpper();
					if (!RegisteredExporters.ContainsKey(key))
						throw new CommandLineException(string.Format(Resources.UnknownExporter, string.Join(", ", RegisteredExporters.Keys)));
					exporterType = RegisteredExporters[key];
					effectiveArgs = args.Skip(1).ToArray();
				}
			}

			var command = (ExportCommandBase)Activator.CreateInstance(exporterType);
			return command;
		}
	}
}
